#region Namespace References

using System;
using System.Collections.Generic;
using System.Xml;

#endregion

namespace DynConDevCorp.OpenArch.SmartData.Persistance
{
    /// <summary>
    /// 
    /// </summary>
    public class StructuredXmlReader
    {
        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="StructuredXmlReader"/> class.
        /// </summary>
        /// <param name="xmlReader">The XML reader.</param>
        protected StructuredXmlReader(XmlReader xmlReader)
        {
            m_XmlReader = xmlReader;
        }

        #endregion

        #region Public Delegates

        /// <summary>
        /// 
        /// </summary>
        public delegate void ElementHandler(string parentElementName);

        #endregion

        #region Protected Instance Methods

        /// <summary>
        /// Processes the segment.
        /// </summary>
        /// <param name="parentElementName">Name of the parent element.</param>
        /// <param name="dispatch">The dispatch.</param>
        protected void ProcessSegment(string parentElementName, ElementDispatch dispatch)
        {
            bool done = false;
            string currentElementName = null;
            while (!done)
            {
                ReadNode();
                switch (m_CurrentNodeType)
                {
                    case XmlNodeType.Element:
                        {
                            currentElementName = m_CurrentNodeName;
                            ElementHandler handler;
                            if (dispatch.TryGetValue(currentElementName, out handler))
                                handler(currentElementName);
                            else
                                throw new Exception();
                        }
                        break;
                    case XmlNodeType.EndElement:
                        if (m_CurrentNodeName == parentElementName)
                        {
                            if ((m_PeekNodeType == XmlNodeType.Element) && dispatch.ContainsKey(m_PeekNodeName))
                            {
                            }
                            else
                            {
                                done = true;
                            }
                        }
                        else if (m_CurrentNodeName != currentElementName)
                        {
                            throw new Exception();
                        }
                        break;
                    case XmlNodeType.None:
                        done = true;
                        break;
                    default:
                        throw new Exception();
                }
            }
        }

        /// <summary>
        /// Reads the end node.
        /// </summary>
        /// <param name="openingName">Name of the opening.</param>
        protected void ReadEndNode(string openingName)
        {
            ReadNode();
            if (m_CurrentNodeType != XmlNodeType.EndElement)
                throw new Exception();
            if (m_CurrentNodeName != openingName)
                throw new Exception();
        }

        /// <summary>
        /// Reads the node.
        /// </summary>
        protected void ReadNode()
        {
            m_CurrentNodeType = m_PeekNodeType;
            m_CurrentNodeName = m_PeekNodeName;
            m_CurrentNodeValue = m_PeekNodeValue;
            m_XmlReader.Read();
            m_PeekNodeType = m_XmlReader.NodeType;
            m_PeekNodeName = m_XmlReader.Name;
            m_PeekNodeValue = m_XmlReader.Value;
        }

        /// <summary>
        /// Reads the node value.
        /// </summary>
        /// <returns></returns>
        protected object ReadNodeValue()
        {
            ReadNode();
            if (m_CurrentNodeType != XmlNodeType.Text)
                throw new Exception();
            return m_CurrentNodeValue;
        }

        #endregion

        #region Fields and Constants

        private readonly XmlReader m_XmlReader;

        /// <summary>
        /// 
        /// </summary>
        protected String m_CurrentNodeName;

        /// <summary>
        /// 
        /// </summary>
        protected XmlNodeType m_CurrentNodeType;

        /// <summary>
        /// 
        /// </summary>
        protected object m_CurrentNodeValue;

        /// <summary>
        /// 
        /// </summary>
        protected String m_PeekNodeName = String.Empty;

        /// <summary>
        /// 
        /// </summary>
        protected XmlNodeType m_PeekNodeType = XmlNodeType.Whitespace;

        /// <summary>
        /// 
        /// </summary>
        protected object m_PeekNodeValue;

        #endregion

        #region Nested type: ElementDispatch

        /// <summary>
        /// 
        /// </summary>
        public class ElementDispatch : Dictionary<string, ElementHandler>
        {
        }

        #endregion
    }
}